/*
 * gateway.c
 *
 *  Created on: Mar 16, 2024
 *      Author: 25119
 */

#include "gateway.h"
#include "tim.h"

// 函数用于检查MAC是否存在
static uint8_t node_scan_is_mac_exist(Node_scan *node_scan, uint8_t *new_mac)
{
  for (uint8_t i = 0; i < node_scan->cnt; ++i)
  {
    uint8_t idx = (node_scan->head + i) % MAX_SCAN_NODES;
    if (memcmp(node_scan->mac[idx], new_mac, 6) == 0)
    {
      return 1; // MAC存在
    }
  }
  return 0; // MAC不存在
}

// 添加新节点，如果已经存在了，则返回1，否则返回0
static int node_scan_new(Node_scan *node_scan, uint8_t *new_mac)
{
  // 检查MAC地址是否已存在
  if (!node_scan_is_mac_exist(node_scan, new_mac))
  {
    // 将新MAC添加到队列中
    memcpy(node_scan->mac[node_scan->tail], new_mac, 6);

    // 更新计数和尾部位置
    node_scan->tail = (node_scan->tail + 1) % MAX_SCAN_NODES;
    if (node_scan->cnt < MAX_SCAN_NODES)
    {
      node_scan->cnt++;
    }
    else
    {
      // 如果队列已满，移动头部以覆盖最老的节点
      node_scan->head = (node_scan->head + 1) % MAX_SCAN_NODES;
    }

    return 0;
  }

  return 1;
}

/* 输入输出不能是同一个数组 */
static void reverse_bytes(uint8_t *data_out, uint8_t *data_in, int length)
{
  int i = 0;
  int j = length - 1;
  while (i < length)
  {
    *(data_out + i) = *(data_in + j);

    // 移动指针
    i++;
    j--;
  }
}

////////////////////---------A72 Gateway function---------////////////////////
// 重启模块
inline int A72_reboot(Gateway_info *gateway)
{
  return A72_tx_cmd(&GATEWAY_UART_HANDLE, C_A72_T_reboot);
}

// 模块恢复出场设置
inline int A72_restore(Gateway_info *gateway)
{
  return A72_tx_cmd(&GATEWAY_UART_HANDLE, C_A72_T_restore);
}

// 获取MAC地址和通信地址
int A72_get_mac_addr(Gateway_info *gateway)
{
  uint8_t temp[0xA0];
  A72_tx_cmd(&GATEWAY_UART_HANDLE, C_A72_T_read_address);
  A72_rx_cmd(&GATEWAY_UART_HANDLE, temp);
  if (A72_cmd_cmp(temp, C_A72_R_read_address) == 0)
  {
    memcpy(gateway->mac, temp + 2, 8);
  }
  else
  {
    return -1;
  }

  return 0;
}

// 获取程序信息
int A72_get_program_info(Gateway_info *gateway)
{
  uint8_t temp[0x06];
  A72_tx_cmd(&GATEWAY_UART_HANDLE, C_A72_T_read_program_info);
  A72_rx_cmd(&GATEWAY_UART_HANDLE, temp);
  if (A72_cmd_cmp(temp, C_A72_R_read_program_info) == 0)
  {
    memcpy(gateway->program_info, temp + 2, 4);
  }
  else
  {
    return -1;
  }

  return 0;
}

// 获取网关信息，包括入网状态
int A72_get_gateway_info(Gateway_info *gateway)
{
  uint8_t temp[0x1C];
  A72_tx_cmd(&GATEWAY_UART_HANDLE, C_A72_T_get_gateway_info);
  A72_rx_cmd(&GATEWAY_UART_HANDLE, temp);
  if (A72_cmd_cmp(temp, C_A72_R_get_gateway_info) == 0)
  {
    if (temp[2] == 0x00) //未入网
      A72_set_gateway_info(gateway);
    memcpy(gateway->network_key, temp + 3, 16);
  }
  else
  {
    return -1;
  }

  return 0;
}

// 设置网关信息
inline int A72_set_gateway_info(Gateway_info *gateway)
{
  memcpy(C_A72_T_set_gateway_info + C_A72_T_set_gateway_network_key,
      gateway->network_key, 16);
  return A72_tx_cmd(&GATEWAY_UART_HANDLE, C_A72_T_set_gateway_info);
}

// 开始扫描节点
inline int A72_start_scan_node(Gateway_info *gateway)
{
  gateway->node_scan.cnt = gateway->node_scan.head = gateway->node_scan.tail = 0; //但如果加这句的话环形队列就失去作用了，正在考虑怎么改

  return A72_tx_cmd(&GATEWAY_UART_HANDLE, C_A72_T_start_scan);
}

// 停止扫描节点
inline int A72_stop_scan_node(Gateway_info *gateway)
{
  return A72_tx_cmd(&GATEWAY_UART_HANDLE, C_A72_T_stop_scan);
}

// 尝试记录节点，返回一共扫描到了几个节点，但-1表示扫描超时
int A72_try_record_node(Gateway_info *gateway)
{
  uint8_t temp[0x24];
  uint8_t cnt = 0;
  uint8_t same_cnt = 0;
  uint8_t mac[6];
  uint8_t mac_bak[6] = {0};
  int failed_time = 0;
  do
  {
    if (A72_rx_cmd_long_time(&GATEWAY_UART_HANDLE, temp, 2000))
    {
      if (failed_time++ >= 3)
        return -1;
      continue;
    }
    else
    {
      failed_time = 0;
    }

    if (A72_cmd_cmp(temp, C_A72_R_start_scan) == 0)
    {
      reverse_bytes(mac, temp + 2, 6);
#warning 这里应该可以把与mac_bak是否相同的判断给优化掉
      if (memcmp(mac, mac_bak, 6)) //如果上一次得到的mac地址和此次的不一样
      {
        if (node_scan_new(&(gateway->node_scan), mac))
          cnt++;
        else
          cnt = 0;
        memcpy(mac_bak, mac, 6);
        same_cnt = 0;
      }
      else
      {
        same_cnt++;
      }
    }
  }
  while ((cnt < (gateway->node_scan.cnt * 5) || cnt == 0) && same_cnt < 10);

  return gateway->node_scan.cnt;
}

// 扫描、记录、停止，一条龙服务，返回一共扫描到了几个节点，但-1表示扫描超时
int A72_scan_node(Gateway_info *gateway)
{
  int ret = 0;

  A72_start_scan_node(gateway);
  ret = A72_try_record_node(gateway);
  A72_stop_scan_node(gateway);

  return ret;
}

// 提取一个扫描到的节点MAC地址，返回值是存放MAC地址地址（被强制转换为int*了）
inline int scan_node_extract_one_mac(Node_scan *node_scan, uint8_t index)
{
  return (int)(&(node_scan->mac[(node_scan->head + index) % MAX_SCAN_NODES]));
}

// 配置节点参数
int A72_node_param_cfg(Gateway_info *gateway, uint8_t *p_mac, uint16_t addr)
{
  uint8_t temp[50];
  uint8_t *p_data = temp + 1;

  while(A72_rx_cmd_long_time(&GATEWAY_UART_HANDLE, temp, 700) == 0);

  temp[0] = C_A72_T_filter_addr[0] + 6;
  memcpy(temp + 1, C_A72_T_filter_addr + 1, C_A72_T_filter_addr[0]);
  reverse_bytes(temp + 1 + C_A72_T_filter_addr[0], p_mac, 6);
  A72_tx_cmd(&GATEWAY_UART_HANDLE, temp);

  DELAY_MS(50);
  temp[0] = C_A72_T_node_param_cfg_1[0] + 16 + C_A72_T_node_param_cfg_2[0] + 2;
  memcpy(p_data, C_A72_T_node_param_cfg_1 + 1, C_A72_T_node_param_cfg_1[0]);
  p_data += C_A72_T_node_param_cfg_1[0];
  memcpy(p_data, gateway->network_key, 16);
  p_data += 16;
  memcpy(p_data, C_A72_T_node_param_cfg_2 + 1, C_A72_T_node_param_cfg_2[0]);
  p_data += C_A72_T_node_param_cfg_2[0];
  memcpy(p_data, &addr, 2);
  A72_tx_cmd(&GATEWAY_UART_HANDLE, temp);

  int faild_times_1 = 0;
  int faild_times_2 = 0;
  do
  {
    if (A72_rx_cmd_long_time(&GATEWAY_UART_HANDLE, temp, 3000) == 0)
    {
      if (A72_cmd_cmp(temp, C_A72_R_node_param_cfg) == 0)
      {
        if (temp[2] == 0x01) //添加成功
        {
          goto add_success;
        }
      }
      else
      {
        faild_times_2++;
      }

      faild_times_1 = 0;
    }
    else
    {
      faild_times_1++;
    }
  }
  while (faild_times_1 < 3 && faild_times_2 < 40);
  return -1;

  add_success:
  return 0;
}

// 绑定
int faild_times_1 = 0;
int faild_times_2 = 0;
int A72_node_bind(Gateway_info *gateway)
{
  uint8_t temp[100];
  temp[0] = C_A72_T_node_bind[0] + 16;
  memcpy(temp + 1, C_A72_T_node_bind + 1, C_A72_T_node_bind[0]);
  memcpy(temp + 1 + C_A72_T_node_bind[0], gateway->app_key, 16);
  A72_tx_cmd(&GATEWAY_UART_HANDLE, temp);

  faild_times_1 = 0;
  faild_times_2 = 0;
  do
  {
    if (A72_rx_cmd_long_time(&GATEWAY_UART_HANDLE, temp, 3000) == 0)
    {
      if (A72_cmd_cmp(temp, C_A72_R_node_bind) == 0)
      {
        if (temp[2] == 0x00) //绑定成功
        {
          goto bind_success;
        }
      }
      else
      {
        if (faild_times_2++ >= 40)
          break;
      }

      faild_times_1 = 0;
    }
    else
    {
      faild_times_1++;
    }
  }
  while (faild_times_1 < 3);// && faild_times_2 < 40

  faild_times_2 = 0;
  UNUSED(faild_times_2);
  return -1;

  bind_success:
  return 0;
}

//inline int A72_delete_node(uint16_t addr)
//{
//  uint8_t temp[1 + C_A72_T_delete_node_1[0] + 2 + C_A72_T_delete_node_2[0]];
//  uint8_t *pdata  = temp + 1;
//  temp[0] = C_A72_T_delete_node_1[0] + 2 + C_A72_T_delete_node_2[0];
//  memcpy(pdata, C_A72_T_delete_node_1, C_A72_T_delete_node_1[0]);
//  pdata += C_A72_T_delete_node_1[0];
//  memcpy(pdata, &addr, 2);
//  pdata += 2;
//  memcpy(pdata, C_A72_T_delete_node_2, C_A72_T_delete_node_2[0]);
//  return A72_tx_cmd(&GATEWAY_UART_HANDLE, temp);
//}

// 添加节点一条路服务
int A72_add_node(Gateway_info *gateway, uint8_t *p_mac)
{
  int ret = 0;
  uint16_t addr;

  for (uint16_t i = 0; i < MAX_SAVE_NODES; i++)
  {
    // 先检索有无空位保存节点
    if (*(uint16_t*)(&(gateway->node_all[i].addr)) == 0x0000)
    {
      addr = i | 0x1000;

      A72_start_scan_node(gateway);
      DELAY_MS(1000);

      if (A72_node_param_cfg(gateway, p_mac, addr))
      { //如果添加失败
        ret = -1;
        goto func_return;
      }
      DELAY_MS(1000);

      if (A72_node_bind(gateway))
      { //如果绑定失败
        DELAY_MS(500);
        A72_delete_node(addr);
        ret = -2;
        goto func_return;
      }

      *(uint16_t*)(&(gateway->node_all[i].addr)) = addr;
      memcpy(gateway->node_all[i].mac, p_mac, 6);
      gateway->node_cnt++;

      goto func_return;
    }
  }
  ret = -3; //存不下了

  func_return:
  A72_stop_scan_node(gateway);
  return ret;
}

int A72_delete_node(uint16_t addr)
{
  uint8_t temp[1 + C_A72_T_delete_node_1[0] + 2 + C_A72_T_delete_node_2[0]];
  uint8_t *p_data = temp + 1;
  memcpy(p_data, C_A72_T_delete_node_1 + 1, C_A72_T_delete_node_1[0]);
  p_data += C_A72_T_delete_node_1[0];
  memcpy(p_data, (uint8_t*)&addr, 2);
  p_data += 2;
  memcpy(p_data, C_A72_T_delete_node_2 + 1, C_A72_T_delete_node_2[0]);
  temp[0] = C_A72_T_delete_node_1[0] + 2 + C_A72_T_delete_node_2[0];

  A72_tx_cmd(&GATEWAY_UART_HANDLE, temp);
  if (A72_rx_cmd_long_time(&GATEWAY_UART_HANDLE, temp, 300))
    return -1;
  A72_rx_cmd_long_time(&GATEWAY_UART_HANDLE, temp, 300);
  if (A72_cmd_cmp(temp, C_A72_R_delete_node_1) == 0)
  {
    if (memcmp(temp + 2, &addr, 2) == 0)
    {
      return 0;
    }
    else
    {
      return -2;
    }
  }
  return -3;
}

int A72_add_group(uint16_t addr, uint8_t group)
{
  memcpy(C_A72_T_group + C_A72_T_group_addr_1, (uint8_t*)&addr, 2);
  memcpy(C_A72_T_group + C_A72_T_group_op_code, &C_A72_T_add_group_op_code, 1);
  memcpy(C_A72_T_group + C_A72_T_group_addr_2, (uint8_t*)&addr, 2);
  memcpy(C_A72_T_group + C_A72_T_group_group, &group, 1);
  memcpy(C_A72_T_group + C_A72_T_group_others, C_A72_T_group_others_1 + 1, C_A72_T_group_others_1[0]);

  return A72_tx_cmd(&GATEWAY_UART_HANDLE, C_A72_T_group);
}

int A72_delete_group(uint16_t addr, uint8_t group)
{
  memcpy(C_A72_T_group + C_A72_T_group_addr_1, (uint8_t*)&addr, 2);
  memcpy(C_A72_T_group + C_A72_T_group_op_code, &C_A72_T_delete_group_op_code, 1);
  memcpy(C_A72_T_group + C_A72_T_group_addr_2, (uint8_t*)&addr, 2);
  memcpy(C_A72_T_group + C_A72_T_group_group, &group, 1);
  memcpy(C_A72_T_group + C_A72_T_group_others, C_A72_T_group_others_1 + 1, C_A72_T_group_others_1[0]);

  return A72_tx_cmd(&GATEWAY_UART_HANDLE, C_A72_T_group);
}

int A72_delete_all_group(uint16_t addr)
{
  memcpy(C_A72_T_group + C_A72_T_group_addr_1, (uint8_t*)&addr, 2);
  memcpy(C_A72_T_group + C_A72_T_group_op_code, &C_A72_T_delete_all_group_op_code, 1);
  memcpy(C_A72_T_group + C_A72_T_group_addr_2, (uint8_t*)&addr, 2);
  memcpy(C_A72_T_group + C_A72_T_group_group, C_A72_T_group_others_2 + 1, C_A72_T_group_others_2[0]);

  return A72_tx_cmd(&GATEWAY_UART_HANDLE, C_A72_T_group);
}

inline int A72G_uart_rx(UART_HandleTypeDef *huart, uint32_t time_out)
{
  rx_buf.len = 0;
  HAL_StatusTypeDef ret = HAL_UART_Receive(huart, (uint8_t*)&rx_buf.len, 2, time_out);
  if (ret != HAL_OK)
    return -1;
  ret = HAL_UART_Receive(huart, rx_buf.data, rx_buf.len, time_out);
  if (ret != HAL_OK)
    return -2;

  if (A72_cmd_cmp(rx_buf.data, C_A72_R_gateway_uart_rx_1))
    return -3;

  if (A72_cmd_cmp(rx_buf.data + 4, C_A72_R_gateway_uart_rx_2))
    return -4;

  return 0;
}

int A72G_rx_uart_it_cb(UART_HandleTypeDef *huart, bool reset)
{
  static bool head = true;
  static uint8_t flag = 0;

  if (reset)
  {
    HAL_UART_AbortReceive(huart);
    HAL_TIM_Base_Stop_IT(&htim16);
    head = true;
    flag = 0;
  }

  if (head)
  {
    if (flag == 2)
    {
      rx_buf.done = 1;
    }
    flag = 1;
    HAL_UART_Receive_IT(huart, (uint8_t*)&rx_buf.len, 2);
    head = false;
  }
  else
  {
    HAL_UART_Receive_IT(huart, rx_buf.data, rx_buf.len);
    head = true;
    flag = 2;

    TIM16->CNT = 0;
    __HAL_TIM_CLEAR_FLAG(&htim16, TIM_FLAG_UPDATE);
    HAL_TIM_Base_Start_IT(&htim16);
  }

  return 0;
}
